import isString from "lodash/isString";
import forEach from "lodash/forEach";
import filter from "lodash/filter";

if (!window.AUIValidate) {
    throw new Error("need dep validate");
}

export function genForm(formFields, fieldKeys) {
    var ret = {};
    ret.data = {};
    ret.constraints = {};
    ret.element = {};
    ret.errors = {};
    ret.controlErrors = [];
    ret.validatecallbacks = {};
    ret.errorLength = 0;
    ret.private_formFields = formFields;
    forEach(formFields, function (formField, fieldkey) {
        if (fieldKeys.indexOf(fieldkey) > -1) {
            ret.data[fieldkey] = {};
            ret.constraints[fieldkey] = {};
            ret.element[fieldkey] = {};
            ret.errors[fieldkey] = [];
            ret.validatecallbacks[fieldkey] = false;
            if (formField.attr) {
                ret.data[fieldkey] = formField.attr;
            }
            if (formField.validate) {
                ret.constraints[fieldkey] = formField.validate;
            }
            if (formField.onValidate) {
                ret.validatecallbacks[fieldkey] = formField.onValidate;
            }
        }
    });
    ret.validate = function (k, newval, oldval) {
        if (!ret.element[k]) {
            console.error(k + " element 初始化失败");
        }
        var lastErrors = ret.errors[k];
        if (isString(newval) && newval.length < 1) {
            if (ret.element[k].onEmpty) {
                ret.element[k].onEmpty();
            }
        } else {
            if (ret.element[k].onUnEmpty) {
                ret.element[k].onUnEmpty();
            }
        }

        ret.errors[k] = window.AUIValidate.single(newval, ret.constraints[k]);

        if (ret.validatecallbacks[k]) {
            var errors = ret.validatecallbacks[k](newval, oldval, ret.constraints[k], ret);
            if (ret.errors[k] && Object.keys(ret.errors[k]).length > 0) {
                ret.errors[k] = Object.assign(ret.errors[k], errors);
            } else {
                ret.errors[k] = errors;
            }
        }

        if (ret.element[k].onChange) {
            ret.element[k].onChange();
        }
        if (ret.errors[k] && ret.errors[k].length > 0) {
            ret.element[k].isValidateError = true;
            if (ret.element[k].onValidateError) {
                ret.element[k].onValidateError();
            }
        } else {
            ret.element[k].isValidateError = false;
            if (ret.element[k].onValidateSuccess) {
                ret.element[k].onValidateSuccess();
            }
        }
    };
    ret.nottwice = false;
    ret.checkError = function () {
        var uierrors = filter(ret.errors, function (v) {
            return v;
        });
        return ret.nottwice || ret.errorLength > 0 || uierrors.length > 0;
    };
    ret.getFormFields = function () {
        return ret.private_formFields;
    };
    ret.isFieldRequired = function (name) {
        return !ret.data[name].controlnotvalidate && ret.constraints[name].presence;
    };
    ret.validateField = function (name) {
        return ret.validate(name, ret.data[name].value, ret.data[name].value);
    };
    ret.getFieldElement = function (name) {
        return ret.element[name];
    };
    ret.checkErrorByfieldkeys = function (fieldkeys) {
        var uierrorLength = 0;
        var controlerrors = ret.validateByFieldkeys(fieldkeys);
        var controllerror = controlerrors && Object.keys(controlerrors).length > 0;
        forEach(ret.errors, function (errorvalue, errorkey) {
            if (fieldkeys.indexOf(errorkey) > -1) {
                if (errorvalue && errorvalue.length > 0) {
                    uierrorLength++;
                }
            }
        });
        return controllerror || uierrorLength > 0 || ret.nottwice;
    };
    ret.getData = function () {
        var res = {};
        forEach(ret.data, function (v, k) {
            res[k] = v.value;
        });
        return res;
    };
    ret.setDataByProp = function (key, value) {
        if (ret.data[key]) {
            ret.data[key].value = value;
        }
    };
    ret.getDataValueByProp = function (key) {
        if (ret.data[key]) {
            return ret.data[key].value;
        }
    };
    ret.setDataByMap = function (map) {
        forEach(map, function (value, key) {
            ret.setDataByProp(key, value);
        })
    };
    ret.setData = function name(data, excludekeys = []) {
        forEach(fieldKeys, function (fieldkey) {        
            if (data[fieldkey] && excludekeys.indexOf(fieldkey) < 0) {
                ret.data[fieldkey].value = data[fieldkey];
            }
        });
    };
    ret.clear = function (fieldkeys) {
        forEach(fieldkeys, function (fieldkey) {
            if (ret.data[fieldkey]) {
                ret.data[fieldkey].value = '';
            }
        })
    };
    ret.resetError = function (fieldkey) {
        ret.errors[fieldkey] = false;
    };
    ret.clearAll = function () {
        forEach(ret.data, function (v, fieldkey) {
            if (ret.data[fieldkey]) {
                ret.data[fieldkey].value = '';
            }
        })
    };
    ret.changeFormFields = function (formFields, type = "validate") {
        forEach(formFields, function (formField, fieldkey) {
            if (fieldKeys.indexOf(fieldkey) > -1) {
                if (formField.attr) {
                    ret.data[fieldkey] = formField.attr;
                }
                if (formField.validate) {
                    ret.constraints[fieldkey] = formField.validate;
                }
                if (formField.onValidate) {
                    ret.validatecallbacks[fieldkey] = formField.onValidate;
                }
            }
        });
    };
    ret.resetAll = function () {
        ret.clearAll();
        ret.nottwice = false;
        setTimeout(function () {
            forEach(ret.data, function (v, fieldkey) {
                ret.resetError(fieldkey);
            });
            forEach(ret.element, function (v, fieldkey) {
                v.reset();
            });
            ret.errorLength = 0;
        }, 0);
    };
    ret.resetValidateAll = function () {
        ret.nottwice = false;
        setTimeout(function () {
            forEach(ret.data, function (v, fieldkey) {
                ret.resetError(fieldkey);
            });
            forEach(ret.element, function (v, fieldkey) {
                if (v.reset) {
                    v.reset();
                }
            });
            ret.errorLength = 0;
        }, 0);
    };
    ret.validateAll = function (excludeFieldKeys) {
        var isError = false;
        var values = {};
        var constraints = {};
        forEach(ret.data, function (v, k) {
            if (excludeFieldKeys && Array.isArray(excludeFieldKeys) && excludeFieldKeys.indexOf(k) < 0) {
                if (!v.controlnotvalidate) {
                    values[k] = v.value;
                    constraints[k] = ret.constraints[k];
                }
            }                        
        });
        var errors = window.AUIValidate(values, constraints);
        ret.controlErrors = errors;
        if (errors) {
            ret.errorLength = Object.keys(errors).length;
        } else {
            ret.errorLength = 0;
        }
        return errors;
    };
    ret.validateByFieldkeys = function (fieldKeys) {
        var excludekeys = [];
        forEach(ret.constraints, function (v, k) {
            if (fieldKeys && fieldKeys.length > 0 && fieldKeys.indexOf(k) < 0) {
                excludekeys.push(k);
            }
        });
        return ret.validateAll(excludekeys);
    };
    ret.checkDirty = function () {
        return filter(ret.element, function (v) {
            return v.dirty;
        }).length > 0;
    };
    ret.validateUiAll = function (excludeFieldKeys) {
        forEach(ret.data, function (v, k) {
            if (excludeFieldKeys && excludeFieldKeys.length > 0 && excludeFieldKeys.indexOf(k) < 0) {
                if (!v.controlnotvalidate) {
                    ret.validate(k, v.value, ret.data[k].value);
                }
            }
        });
    };
    return ret;
}


export function genFormValidate(context, formName, type = "data") {
    forEach(context[formName].data, function (v, k) {
        context.$watch(`${formName}.${type}.${k}.value`, function (newval, oldval) {
            context[formName].validate(k, newval, oldval);

            if (context[formName].onWatch) {
                context[formName].onWatch(newval, oldval, k, context[formName].constraints[k]);
            }

            context[formName].validateAll();


            if (context[formName].errorLength < 1) {
                if (context[formName].checkIsReady) {
                    context[formName].checkIsReady();
                }
            } else {
                if (context[formName].checkIsError) {
                    context[formName].checkIsError();
                }
            }
        });
    });
}


